package com.zjj.filmcommentapi.controller;


import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.google.common.collect.Maps;
import com.zjj.filmcommentapi.model.User;
import com.zjj.filmcommentapi.service.RobotService;
import com.zjj.filmcommentapi.service.UserService;
import com.zjj.filmcommentapi.utils.AuthenticationUtil;
import com.zjj.filmcommentapi.utils.WebSocketMsgCode;
import io.swagger.annotations.Api;


import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;


import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;


/**
 * 处理WebSocket的所有请求
 */
@Api(value = "websocket相关", tags = "websocket相关")
@ServerEndpoint("/websocket/{token}")
@Component
public class WebSocketController {
    //把服务注入到websocket
    public static UserService userService;
    public static RobotService robotService;
    public static AuthenticationUtil authenticationUtil;
    // 当前在线人数
    private static int onlineCount = 0;
    // 用户session
    private Session session;
    // 用户名称
    private String token;

    private User user;
    //储存所有连接用户
    private static Map<String, WebSocketController> clients = new ConcurrentHashMap<String, WebSocketController>();

    /**
     * 打开连接得到连接的session
     *
     * @param session
     */
    @OnOpen
    public void onOpen(@PathParam("token") String token, Session session) {
        System.out.println(token);

        if (!authenticationUtil.fliterLogin(token)) {
            System.out.println("进来了");
            return;
        }
        this.session = session;
        this.token = token;
        this.user = userService.getUserInfo(token);
        try {
            //把自己的信息加入到map当中去
            clients.put(user.getAccount(), this);
            addOnlineCount();
            Set<String> set = clients.keySet();
            //messageType 1代表上线 2代表下线 3代表在线名单 4代表普通消息
            //先给所有人发送通知，说我上线了
            sendMessageAll(getMapToJson(WebSocketMsgCode.UP_STATE, "系统消息:" + user.getName() + "上线了", user, "所有人", set));
            //给自己发一条消息：告诉自己现在都有谁在线
            sendMessageTo(getMapToJson(WebSocketMsgCode.LIST_STATE, "系统消息:", new User(), "自己", set), user.getAccount());
            System.out.println("有一个用户连接成功,当前在线人数：" + getOnlineCount());
        } catch (Exception e) {
            System.out.println(user.getAccount() + "上线时发生错误");
        }
    }

    /**
     * 关闭连接
     */
    @OnClose
    public void onClose() {
        clients.remove(user.getAccount());
        subOnlineCount();
        try {
            //messageType 1代表上线 2代表下线 3代表在线名单  4代表普通消息
            sendMessageAll(getMapToJson(WebSocketMsgCode.DOWN_STATE, "系统消息：" + user.getName() + "下线了", user, "所有人", clients.keySet()));
        } catch (IOException e) {
            System.out.println(user.getAccount() + "下线的时候通知所有人发生了错误");
        }
        System.out.println("有一个用户关闭连接,当前在线人数：" + getOnlineCount());
    }

    /**
     * 给客户端发送消息
     *
     * @param session
     * @throws IOException
     */
    @OnMessage
    public void onMessage(String info, Session session) throws IOException {
        try {
            JSONObject jsonObject = JSON.parseObject(info);
            String textMessage = jsonObject.getString("message");
            String fromToken = jsonObject.getString("token");
            String toAccount = jsonObject.getString("to");
            //如果不是发给所有，那么就发给某一个人
            //messageType 1代表上线 2代表下线 3代表在线名单  4代表普通消息
            User myUser = userService.getUserInfo(fromToken);
            if (toAccount.equals("All")) {
                sendMessageAll(getMapToJson(WebSocketMsgCode.COMMONT_STATE, textMessage, myUser, "所有人", clients.keySet()));
            } else if (toAccount.equals("Robot")) {
                JSONArray result = robotService.postAPI(textMessage, myUser).getJSONArray("results");
                String state = JSONObject.parseObject(result.get(0).toString()).getString("groupType");
                if (state.equals(0)||state.equals("0")){
                    System.out.println("弱智机器人模式");
                    result = robotService.getAPI(textMessage,myUser).getJSONArray("results");
                }
                sendMessageTo(getMapToJson(WebSocketMsgCode.ROBOT_STATE, result, myUser, "自己", clients.keySet()), myUser.getAccount());
            } else {
                sendMessageTo(getMapToJson(WebSocketMsgCode.ROBOT_STATE, textMessage, myUser, "自己", clients.keySet()), toAccount);
            }
        } catch (Exception e) {
            System.out.println("发消息时发生错误");
        }
    }

    /**
     * 发生错误时调用
     *
     * @param session
     * @param error
     * @throws IOException
     */
    @OnError
    public void onError(Session session, Throwable error) throws IOException {
        System.out.println("websocket发生错误");
        sendMessageAll("我炸掉了");
        error.printStackTrace();
    }

    /**
     * 发送消息
     *
     * @param message
     * @throws IOException
     */
    public void sendMessageAll(String message) throws IOException {
        for (WebSocketController item : clients.values()) {
            item.session.getBasicRemote().sendText(message);
        }
    }

    // 发给某个人
    @Async
    public void sendMessageTo(String message, String account) {
        for (WebSocketController item : clients.values()) {
            if (item.user.getAccount().equals(account)) {
                try {
                    item.session.getBasicRemote().sendText(message);
                } catch (IOException e) {
                    e.printStackTrace();
                }
                break;
            }
        }
    }

    /**
     * 封装发送消息的格式
     *
     * @param messageType
     * @param message
     * @param fromUser
     * @param toUser
     * @param onlineUsers
     * @return
     */
    public String getMapToJson(int messageType, Object message, User fromUser, String toUser, Set onlineUsers) {
        Map<String, Object> map = Maps.newHashMap();
        map.put("messageType", messageType);
        map.put("message", message);
        map.put("fromUser", fromUser);
        map.put("toUser", toUser);
        map.put("onlineUsers", onlineUsers);
        return JSON.toJSONString(map);
    }

    //得到在线人数
    public static synchronized int getOnlineCount() {
        return WebSocketController.onlineCount;
    }

    // 添加在线人数
    public static synchronized void addOnlineCount() {
        WebSocketController.onlineCount++;
    }

    // 减少在线人数
    public static synchronized void subOnlineCount() {
        WebSocketController.onlineCount--;
    }

}
